//
// Created by hamlet on 2022/1/14.
//

#ifndef SNAKE_GAME_ROOM_H
#define SNAKE_GAME_ROOM_H

#include <QString>
#include <QSize>
#include "message.h"

class RoomInfo : public Message {
public:
    enum class SizeType : char8_t {
        Big, Medium, Small, Custom
    };
    static constexpr QSize SIZE_BIG    {50, 40};
    static constexpr QSize SIZE_MEDIUM {40, 30};
    static constexpr QSize SIZE_SMALL  {30, 20};

    enum class RoomType : char8_t {
        NoWall, HasWall
    };

    enum class FruitType : char32_t {
        NoneFruit = 0,
        SelfBodyLonger = 1 << 0, OtherBodyShorter = 1 << 1, SelfSpeedUp = 1 << 2, OtherSpeedDown = 1 << 3,
        SelfReverse = 1 << 4, OtherReverse = 1 << 5, LifeIncrease = 1 << 6, ScoreIncrease = 1 << 7,
        TimeIncrease = 1 << 8, TimeDecrease = 1 << 9, LifeDecrease = 1 << 10, ScoreDecrease = 1 << 11,
    };

    RoomInfo(QUrl url, QString name, SizeType sizeType, RoomType roomType, int playerNum, int gameNum, int time,
             int life, FruitType fruitType, int fruitAmount, QSize size = {}, qint64 id = 0LL);
    ~RoomInfo() override = default;
    static RoomInfo *parseJson(const QJsonObject &json);
    [[nodiscard]] QJsonObject toJson() const override;

    [[nodiscard]] QString simpleInfo();
    [[nodiscard]] QString fullInfo();

private:
    qint64 m_ID;
    QUrl m_url;
    QString m_name;
    SizeType m_sizeType;
    QSize m_size;
    RoomType m_roomType;
    int m_playerNum;      // 2~99
    int m_gameNum;        // 1~99
    int m_time;           // 60~1800
    int m_life;           // 1~100
    FruitType m_fruitType;
    int m_fruitAmount;    // 30~100

public:
    [[nodiscard]] qint64 getID() const { return m_ID; }
    [[nodiscard]] const QUrl &getURL() const { return m_url; }
    [[nodiscard]] SizeType getSizeType() const { return m_sizeType; }
    [[nodiscard]] const QSize &getSize() const { return m_size; }
};

constexpr RoomInfo::FruitType operator|(RoomInfo::FruitType a, RoomInfo::FruitType b) {
    return static_cast<RoomInfo::FruitType>(static_cast<char32_t>(a) | static_cast<char32_t>(b));
}

constexpr RoomInfo::FruitType operator&(RoomInfo::FruitType a, RoomInfo::FruitType b) {
    return static_cast<RoomInfo::FruitType>(static_cast<char32_t>(a) & static_cast<char32_t>(b));
}

#endif //SNAKE_GAME_ROOM_H
